﻿/*------------------------------------------------------------------------

C3DNODE.HPP v1.2.8

Copyright 楊志賢 CxxlMan, 2012 - 2014
All Rights Reserved

Cxx3D 重要的空間節點架構，每個節點包含一個 World Matrix4x4，以及 0 ～ 多個
子節點，當父節點的 World Matrix4x4 有變動時，也會把變動的因素傳遞給子孫節點，
以同步變動子孫節點的 World Matrix4x4

子節點可以連結到多個父節點，但內部只記錄父節點有哪些子節點，並不記子節點的
父節點是誰，子節點若連結到多個父節點，會同時受這些父節點變動的影響

每個節點代表一個空間座標，可被多個 3D 物件所依附，但節點內部不記錄被哪些物件
依附，物件須自己持有自己的空間節點

------------------------------------------------------------------------*/

#if !defined(__C3DNODE_HPP_Cxxl3D)
#define __C3DNODE_HPP_Cxxl3D

#include <CENTRALIZEDMGR.HPP>
#include <Sys\MATRIX.HPP>
#include <Sys\CSMART_PTR.HPP>



// 元件介面的識別碼
#define IC3D_Node_ClassID L"E58F6540-738E-49e4-A930-A471A7872657"


namespace Cxxl3D
{

class IC3D_Node:virtual public CxxlMan::cxxlPreserve2
{
  // 複製傳回 World Matrix4x4
  virtual CxxlMan::CSmart_Ptr<Matrix4x4> cxxlFASTCALL CloneWorldMatrix() const = 0;

protected:

  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F) = 0
  {
    if(F != NULL && cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }


public:
  // Constructor
  IC3D_Node()
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(IC3D_Node_ClassID)
  {
  }

  // Destructor
  virtual ~IC3D_Node()
  {
  }

  // 產生新的子節點，並為它產生一個和本身所用，內容相同的 World Matrix(複製的方式)
  virtual CxxlMan::Smart_Ptr<IC3D_Node> cxxlFASTCALL NewChdNode() = 0;

  // 加入指定的子節點，若會造成節點循環，加入失敗並回覆 false
  virtual bool cxxlFASTCALL AttachChdNode(const CxxlMan::Smart_Ptr<IC3D_Node> &ChdNode_Arg) = 0;

  // 分離指定的子節點
  virtual void cxxlFASTCALL DetachChdNode(const CxxlMan::Smart_Ptr<IC3D_Node> &ChdNode_Arg) = 0;

  // 直接配置 World Matrix4x4
  virtual void cxxlFASTCALL AssignWorldMatrix(const CxxlMan::CSmart_Ptr<const Matrix4x4> &Matrix4x4_Arg) = 0;

  // 傳回 World Matrix4x4
  virtual CxxlMan::CSmart_Ptr<const Matrix4x4> cxxlFASTCALL GetWorldMatrix() const = 0;


  // 位移，以世界座標為參考座標
  virtual void cxxlFASTCALL Translate_W(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z) = 0;
  // 位移，以 IC3D_Node 的局部座標為參考座標
  virtual void cxxlFASTCALL Translate_L(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z) = 0;


  // 旋轉，以世界座標為參考座標
  virtual void cxxlFASTCALL Rotate_W(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z, const C3D_FLOAT radian) = 0;
  // 旋轉，以 IC3D_Node 的局部座標為參考座標
  virtual void cxxlFASTCALL Rotate_L(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z, const C3D_FLOAT radian) = 0;


  // 縮放，以世界座標為參考座標
  virtual void cxxlFASTCALL Scale_W(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z) = 0;
  // 縮放，以 IC3D_Node 的局部座標為參考座標
  virtual void cxxlFASTCALL Scale_L(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z) = 0;


  // 建立 IC3D_Node 物件，失敗傳回 NULL
  static CxxlMan::Smart_Ptr<IC3D_Node> cxxlFASTCALL Create(const CxxlMan::CSmart_Ptr<const Matrix4x4> &Matrix4x4 = new Matrix4x4( Matrix4x4::IdentityCreate() ))
  {
    return CxxlMan::Preserve2_Cast<IC3D_Node>( CxxlMan::cxxlCM_GetElement(IC3D_Node_ClassID, CXXL3DDEFAULTGROUP, (void *)&Matrix4x4) );
  }

  // 從永存資料產生 IC3D_Node 物件並取回永存資料
  // 失敗傳回 NULL
  static CxxlMan::Smart_Ptr<IC3D_Node> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &BackupName, const CxxlMan::Smart_Ptr<CxxlMan::IcxxlStorage> &IcxxlStorage_Arg)
  {
    CxxlMan::Smart_Ptr<cxxlPreserve2> cxxlPreserve2_Ptr(NULL);
    CxxlMan::REGENERARETURN_TYPE rt = cxxlCM_Regenera(cxxlPreserve2_Ptr, BackupName, IcxxlStorage_Arg, true);
    if(rt == CxxlMan::Regenera_Success)
      return CxxlMan::Smart_Cast<IC3D_Node>(cxxlPreserve2_Ptr);
    return NULL;
  }


  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IC3D_Node>;  // Preserve2 元件須加上這個
};

// 要放入 IC3D_Node 的物件就繼承這個介面吧
class IC3D_NodeHost:virtual public CxxlMan::cxxlPreserve2
{

  // 依附的 IC3D_Node
  CxxlMan::P2Smart_Ptr<IC3D_Node> m_IC3D_Node_Ptr;

protected:

  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F) = 0
  {
    if(F != NULL && cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

  // Constructor
  IC3D_NodeHost()
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(L""),
    m_IC3D_Node_Ptr(NULL,this,L"IC3D_Node")
  {

  }

public:
  // Destructor
  virtual ~IC3D_NodeHost()
  {

  }

  // 設定依附的 IC3D_Node
  void cxxlFASTCALL Depend_IC3D_Node(const CxxlMan::Smart_Ptr<IC3D_Node> &IC3D_Node_Arg)
  {
    csPreserve.Enter();
    m_IC3D_Node_Ptr = IC3D_Node_Arg;
    csPreserve.Leave();
  }

  // 取得依附的 IC3D_Node
  CxxlMan::Smart_Ptr<IC3D_Node> cxxlFASTCALL Get_IC3D_Node() const
  {
    CxxlMan::CriticalSecHandle AutoCSH(csPreserve);
    return (IC3D_Node *)m_IC3D_Node_Ptr;
  }

};

// 初始化，這裡只做元件註冊
inline void IC3D_Node_Init()
{
  CxxlMan::cxxlCM_ElementReg(IC3D_Node_ClassID, CXXL3DDEFAULTGROUP, L"C3dLib.dll");
}



}   /* namespace Cxxl3D */
#endif
